﻿// -----------------------------------------------------------------------
// <copyright file="AES.cs" company="Hewlett-Packard">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace SecutityLib
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class AES : EncodingDecodingTech
    {
        /// <summary>
        /// Round constants used at key generation
        /// </summary>
        private byte[] roundConst = { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 };

        /// <summary>
        /// S box values
        /// </summary>
        private byte[,] sboxAES = 
        { 
                                  { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76 }, 
                                  { 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0 }, 
                                  { 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15 }, 
                                  { 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75 }, 
                                  { 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84 }, 
                                  { 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf },
                                  { 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8 }, 
                                  { 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2 }, 
                                  { 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73 }, 
                                  { 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb }, 
                                  { 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79 }, 
                                  { 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08 }, 
                                  { 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a }, 
                                  { 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e },
                                  { 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf }, 
                                  { 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 } 
                                  };

        /// <summary>
        /// inverse s box values
        /// </summary>
        private byte[,] inverseSboxAES =
        { 
                                         { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb }, 
                                         { 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb }, 
                                         { 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e }, 
                                         { 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 }, 
                                         { 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92 },
                                         { 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 },
                                         { 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06 },
                                         { 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b }, 
                                         { 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73 }, 
                                         { 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e }, 
                                         { 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b }, 
                                         { 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4 }, 
                                         { 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f }, 
                                         { 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef }, 
                                         { 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 },
                                         { 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d } 
                                         };

        /// <summary>
        /// Encodes the specified plain text.
        /// </summary>
        /// <param name="plainText">The plain text.</param>
        /// <param name="key">The key.</param>
        /// <returns>
        /// cipher text
        /// </returns>
        public override string Encode(string plainText, string key)
        {
            try
            {
                byte[,] keyMatrix = this.GetTextMatrix(key);

                byte[,] plainMatrix = this.GetTextMatrix(plainText);

                plainMatrix = this.AddRoundKey(plainMatrix, keyMatrix);

                for (int i = 1; i < 10; i++)
                {
                    plainMatrix = this.SubstituteBytes(plainMatrix);
                    plainMatrix = this.ShiftRows(plainMatrix);
                    plainMatrix = this.MixColumns(plainMatrix);
                    keyMatrix = this.GetNextKey(keyMatrix, i);
                    plainMatrix = this.AddRoundKey(keyMatrix, plainMatrix);
                }

                plainMatrix = this.SubstituteBytes(plainMatrix);
                plainMatrix = this.ShiftRows(plainMatrix);
                keyMatrix = this.GetNextKey(keyMatrix, 10);
                plainMatrix = this.AddRoundKey(keyMatrix, plainMatrix);

                return this.ConvertBytesToHex(plainMatrix) + "\r\n" + this.ConvertBytesToChar(plainMatrix);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Decodes the specified plain text.
        /// </summary>
        /// <param name="cipherText">The cipher text.</param>
        /// <param name="key">The key.</param>
        /// <returns>
        /// cipher text
        /// </returns>
        public override string Decode(string cipherText, string key)
        {
            try
            {
                byte[,] keyMatrix = this.GetTextMatrix(key);

                byte[,] cipherMatrix = this.GetTextMatrix(cipherText);

                List<byte[,]> roundKeys = new List<byte[,]>();
                roundKeys.Add(keyMatrix);

                for (int i = 1; i < 11; i++)
                {
                    roundKeys.Add(this.GetNextKey(roundKeys[i - 1], i));
                }

                cipherMatrix = this.AddRoundKey(cipherMatrix, roundKeys[10]);

                for (int i = 9; i > 0; i--)
                {
                    cipherMatrix = this.InverseShiftRows(cipherMatrix);
                    cipherMatrix = this.InverseSubstituteBytes(cipherMatrix);
                    cipherMatrix = this.AddRoundKey(cipherMatrix, roundKeys[i]);
                    cipherMatrix = this.InverseMixColumns(cipherMatrix);
                }

                cipherMatrix = this.InverseShiftRows(cipherMatrix);
                cipherMatrix = this.InverseSubstituteBytes(cipherMatrix);
                cipherMatrix = this.AddRoundKey(cipherMatrix, roundKeys[0]);

                return this.ConvertBytesToHex(cipherMatrix) + "\r\n" + this.ConvertBytesToChar(cipherMatrix);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Mixes the columns.
        /// </summary>
        /// <param name="stateMatrix">The state matrix.</param>
        /// <returns>mix columns</returns>
        private byte[,] MixColumns(byte[,] stateMatrix)
        {
            try
            {
                byte[,] constantMatrix = { { 0x02, 0x03, 0x01, 0x01 }, { 0x01, 0x02, 0x03, 0x01 }, { 0x01, 0x01, 0x02, 0x03 }, { 0x03, 0x01, 0x01, 0x02 } };

                byte[,] retMat = new byte[4, 4];

                for (int i = 0; i < 4; i++)
                {
                    for (int j = 0; j < 4; j++)
                    {
                        byte sum = 0;
                        for (int k = 0; k < 4; k++)
                        {
                            sum ^= this.MultiplyUnderGF(constantMatrix[i, k], stateMatrix[k, j]);
                        }

                        retMat[i, j] = sum;
                    }
                }

                return retMat;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Inverses the mix columns.
        /// </summary>
        /// <param name="stateMatrix">The state matrix.</param>
        /// <returns>mix col inverse</returns>
        private byte[,] InverseMixColumns(byte[,] stateMatrix)
        {
            try
            {
                byte[,] constantMatrixInverse = { { 0x0E, 0x0B, 0x0D, 0x09 }, { 0x09, 0x0E, 0x0B, 0x0D }, { 0x0D, 0x09, 0x0E, 0x0B }, { 0x0B, 0x0D, 0x09, 0x0E } };

                byte[,] retMat = new byte[4, 4];

                for (int i = 0; i < 4; i++)
                {
                    for (int j = 0; j < 4; j++)
                    {
                        byte sum = 0;
                        for (int k = 0; k < 4; k++)
                        {
                            sum ^= this.MultiplyUnderGF(constantMatrixInverse[i, k], stateMatrix[k, j]);
                        }

                        retMat[i, j] = sum;
                    }
                }

                return retMat;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Multiplies the under GF.
        /// </summary>
        /// <param name="one">The one.</param>
        /// <param name="two">The two.</param>
        /// <returns>the val after mul using gf (8)</returns>
        private byte MultiplyUnderGF(byte one, byte two)
        {
            try
            {
                if (one == 0x01)
                {
                    return two;
                }
                else if (one == 0x02)
                {
                    byte temp = 0x80;
                    bool bitNo7 = (two & temp) == temp ? true : false;
                    if (bitNo7 == false)
                    {
                        return (byte)(two << 1);
                    }
                    else
                    {
                        return (byte)((two << 1) ^ 0x1b);
                    }
                }
                else if (one == 0x03)
                {
                    return (byte)(this.MultiplyUnderGF((byte)0x01, two) ^ this.MultiplyUnderGF((byte)0x02, two));
                }
                else if (one == 0x09)
                {
                    // x^3 +1
                    byte temp = this.MultiplyUnderGF((byte)0x02, two); // *x
                    temp = this.MultiplyUnderGF((byte)0x02, temp); // *x2
                    temp = this.MultiplyUnderGF((byte)0x02, temp); // *x3
                    return (byte)(this.MultiplyUnderGF((byte)0x01, two) ^ temp);
                }
                else if (one == 0x0B)
                {
                    // x^3 + x + 1--> 9 + 2
                    byte temp = this.MultiplyUnderGF((byte)0x09, two); // *x3+1
                    return (byte)(this.MultiplyUnderGF((byte)0x02, two) ^ temp);
                }
                else if (one == 0x0D)
                {
                    // x^3 + x2 + 1--> 9 + x2
                    byte temp = this.MultiplyUnderGF((byte)0x09, two); // *x3+1
                    byte temp2 = this.MultiplyUnderGF((byte)0x02, two); // x
                    temp2 = this.MultiplyUnderGF((byte)0x02, temp2); // x2
                    return (byte)(temp2 ^ temp);
                }
                else if (one == 0x0E)
                {
                    // x^3 + x2 + x
                    byte temp = this.MultiplyUnderGF((byte)0x02, two); // x
                    byte temp2 = this.MultiplyUnderGF((byte)0x02, temp); // x2
                    byte temp3 = this.MultiplyUnderGF((byte)0x02, temp2); // x3
                    return (byte)(temp2 ^ temp ^ temp3);
                }
                else
                {
                    throw new Exception("undefined multiplication under GF 2^8");
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Substitutes the bytes.
        /// </summary>
        /// <param name="stateMatrix">The state matrix.</param>
        /// <returns>sub bytes</returns>
        private byte[,] SubstituteBytes(byte[,] stateMatrix)
        {
            try
            {
                for (int i = 0; i < stateMatrix.GetLength(0); i++)
                {
                    for (int j = 0; j < stateMatrix.GetLength(1); j++)
                    {
                        stateMatrix[i, j] = this.GetValueFromSbox(stateMatrix[i, j]);
                    }
                }

                return stateMatrix;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Gets the value from sbox.
        /// </summary>
        /// <param name="val">The val.</param>
        /// <returns>the value from s box inverse</returns>
        private byte GetValueFromSbox(byte val)
        {
            try
            {
                int rowNumber = (val & 0xF0) >> 4;
                int colNumber = val & 0x0F;

                return this.sboxAES[rowNumber, colNumber];
            }
            catch
            {
                throw new Exception("Value not correct for SBOX");
            }
        }

        /// <summary>
        /// Inverses the substitute bytes.
        /// </summary>
        /// <param name="stateMatrix">The state matrix.</param>
        /// <returns>sub byte inverse</returns>
        private byte[,] InverseSubstituteBytes(byte[,] stateMatrix)
        {
            try
            {
                for (int i = 0; i < stateMatrix.GetLength(0); i++)
                {
                    for (int j = 0; j < stateMatrix.GetLength(1); j++)
                    {
                        stateMatrix[i, j] = this.GetValueFromInverseSbox(stateMatrix[i, j]);
                    }
                }

                return stateMatrix;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Gets the value from inverse sbox.
        /// </summary>
        /// <param name="val">The val.</param>
        /// <returns>the value from s box inverse</returns>
        private byte GetValueFromInverseSbox(byte val)
        {
            try
            {
                int rowNumber = (val & 0xF0) >> 4;
                int colNumber = val & 0x0F;

                return this.inverseSboxAES[rowNumber, colNumber];
            }
            catch
            {
                throw new Exception("Value not correct for SBOX inverse");
            }
        }

        /// <summary>
        /// Shifts the rows.
        /// </summary>
        /// <param name="stateMatrix">The state matrix.</param>
        /// <returns>shift rows</returns>
        private byte[,] ShiftRows(byte[,] stateMatrix)
        {
            try
            {
                byte[,] returnedState = new byte[4, 4];
                for (int i = 0; i < 4; i++)
                {
                    for (int j = 0; j < 4; j++)
                    {
                        if (i == 0)
                        {
                            returnedState[i, j] = stateMatrix[i, j];
                        }
                        else if (i == 1)
                        {
                            returnedState[i, j] = stateMatrix[i, (j + 1) % 4];
                        }
                        else if (i == 2)
                        {
                            returnedState[i, j] = stateMatrix[i, (j + 2) % 4];
                        }
                        else if (i == 3)
                        {
                            returnedState[i, j] = stateMatrix[i, (j + 3) % 4];
                        }
                    }
                }

                return returnedState;
            }
            catch
            {
                throw new Exception("Error Shift rows");
            }
        }

        /// <summary>
        /// Inverses the shift rows.
        /// </summary>
        /// <param name="stateMatrix">The state matrix.</param>
        /// <returns>
        /// inverse shift shows
        /// </returns>
        private byte[,] InverseShiftRows(byte[,] stateMatrix)
        {
            try
            {
                byte[,] returnedState = new byte[4, 4];
                for (int i = 0; i < 4; i++)
                {
                    for (int j = 0; j < 4; j++)
                    {
                        if (i == 0)
                        {
                            returnedState[i, j] = stateMatrix[i, j];
                        }
                        else if (i == 1)
                        {
                            returnedState[i, j] = stateMatrix[i, (j + 3) % 4];
                        }
                        else if (i == 2)
                        {
                            returnedState[i, j] = stateMatrix[i, (j + 2) % 4];
                        }
                        else if (i == 3)
                        {
                            returnedState[i, j] = stateMatrix[i, (j + 1) % 4];
                        }
                    }
                }

                return returnedState;
            }
            catch
            {
                throw new Exception("Error Shift rows");
            }
        }

        /// <summary>
        /// Gets the text matrix.
        /// </summary>
        /// <param name="s">The s.</param>
        /// <returns>text matrix</returns>
        private byte[,] GetTextMatrix(string s)
        {
            if (s[0] == '0' && s[1] == 'x')
            {
                s = s.Substring(2);

                if (s.Length != 32)
                {
                    throw new Exception("text must be 16 bytes");
                }

                try
                {
                    byte[,] textMatrix = new byte[4, 4];

                    int indX = 0;
                    int indY = 0;

                    for (int i = 0; i < s.Length; i += 2)
                    {
                        textMatrix[indX, indY] = this.GetByte(s.Substring(i, 2));
                        indY++;
                        if (indY == 4)
                        {
                            indX++;
                            indY = 0;
                        }
                    }

                    return textMatrix;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            else
            {
                try
                {
                    if (s.Length != 16)
                    {
                        throw new Exception("text must be 16 bytes");
                    }

                    byte[,] textMatrix = new byte[4, 4];

                    int indX = 0;
                    int indY = 0;

                    for (int i = 0; i < s.Length; i++)
                    {
                        textMatrix[indX, indY] = (byte)s[i];
                        indY++;
                        if (indY == 4)
                        {
                            indX++;
                            indY = 0;
                        }
                    }

                    return textMatrix;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }

        /// <summary>
        /// Gets the byte.
        /// </summary>
        /// <param name="p">The p.</param>
        /// <returns>byte from string hex val</returns>
        private byte GetByte(string p)
        {
            try
            {
                return byte.Parse(p, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
            }
            catch
            {
                throw new Exception("Error converting string to byte");
            }
        }

        /// <summary>
        /// Gets the next key.
        /// </summary>
        /// <param name="currentKey">The current key.</param>
        /// <param name="roundNumber">The round number.</param>
        /// <returns>next key</returns>
        private byte[,] GetNextKey(byte[,] currentKey, int roundNumber)
        {
            try
            {
                byte[,] keytemp = new byte[4, 4];

                for (int i = 0; i < 4; i++)
                {
                    for (int j = 0; j < 4; j++)
                    {
                        if (j == 3)
                        {
                            keytemp[i, j] = currentKey[(i + 1) % 4, j];
                            keytemp[i, j] = this.GetValueFromSbox(keytemp[i, j]);
                            if (i == 0)
                            {
                                keytemp[i, j] = (byte)(keytemp[i, j] ^ this.roundConst[roundNumber]);
                            }
                        }
                        else
                        {
                            keytemp[i, j] = currentKey[i, j];
                        }
                    }
                }

                byte[,] resKey = new byte[4, 4];

                for (int i = 0; i < 4; i++)
                {
                    for (int j = 0; j < 4; j++)
                    {
                        if (j == 0)
                        {
                            resKey[i, j] = (byte)(keytemp[i, 3] ^ currentKey[i, j]);
                        }
                        else
                        {
                            resKey[i, j] = (byte)(resKey[i, j - 1] ^ currentKey[i, j]);
                        }
                    }
                }

                return resKey;
            }
            catch
            {
                throw new Exception("Error generating next key");
            }
        }

        /// <summary>
        /// Adds the round key.
        /// </summary>
        /// <param name="plain">The plain.</param>
        /// <param name="key">The key.</param>
        /// <returns>xor of key and plain</returns>
        private byte[,] AddRoundKey(byte[,] plain, byte[,] key)
        {
            try
            {
                byte[,] temp = new byte[4, 4];
                for (int i = 0; i < 4; i++)
                {
                    for (int j = 0; j < 4; j++)
                    {
                        temp[i, j] = (byte)(plain[i, j] ^ key[i, j]);
                    }
                }

                return temp;
            }
            catch
            {
                throw new Exception("Error Add round key");
            }
        }

        /// <summary>
        /// Converts the bytes to hex.
        /// </summary>
        /// <param name="plainMatrix">The plain matrix.</param>
        /// <returns>string resulted hex</returns>
        private string ConvertBytesToHex(byte[,] plainMatrix)
        {
            try
            {
                string text = string.Empty;
                for (int i = 0; i < 4; i++)
                {
                    for (int j = 0; j < 4; j++)
                    {
                        byte[] temp = new byte[1];
                        temp[0] = plainMatrix[i, j];
                        text += BitConverter.ToString(temp, 0);
                        text += " ";
                    }
                }

                return text;
            }
            catch
            {
                throw new Exception("Error converting bytes to text");
            }
        }

        /// <summary>
        /// Converts the bytes to char.
        /// </summary>
        /// <param name="plainMatrix">The plain matrix.</param>
        /// <returns>string corresponding to the bytes</returns>
        private string ConvertBytesToChar(byte[,] plainMatrix)
        {
            try
            {
                string text = string.Empty;
                for (int i = 0; i < 4; i++)
                {
                    for (int j = 0; j < 4; j++)
                    {
                        text += (char)plainMatrix[i, j];
                    }
                }

                return text;
            }
            catch
            {
                throw new Exception("Error converting bytes to text");
            }
        }
    }
}
